#pragma once

namespace micro{
namespace gui{



class QToolTip: public QWindow
{
	

	struct QToolInfo : public TOOLINFO
	{
	public:
		QToolInfo(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = nullptr, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = 0)
		{
			Init(nFlags, hWnd, nIDTool, lpRect, lpstrText, lUserParam);
		}

		operator LPTOOLINFO() { return this; }

		operator LPARAM() { return (LPARAM)this; }

		void Init(UINT nFlags, HWND hWnd, UINT nIDTool = 0, LPRECT lpRect = nullptr, LPTSTR lpstrText = LPSTR_TEXTCALLBACK, LPARAM lUserParam = 0)
		{
			ASSERT(::IsWindow(hWnd));
			memset(this, 0, sizeof(TOOLINFO));
			cbSize = sizeof(TOOLINFO);
			uFlags = nFlags;
			if(nIDTool == 0)
			{
				hwnd = ::GetParent(hWnd);
				uFlags |= TTF_IDISHWND;
				uId = (UINT_PTR)hWnd;
			}
			else
			{
				hwnd = hWnd;
				uId = nIDTool;
			}
			if(lpRect != nullptr)
				rect = *lpRect;
			hinst = GetModuleHandle(0);
			lpszText = lpstrText;
			lParam = lUserParam;
		}
	};




	LPCTSTR m_str;
public:
	// Constructors
	QToolTip(HWND hWnd = nullptr) : QWindow(hWnd)
	{ }

	QToolTip(LPCTSTR lpStr) : m_str(lpStr)
	{ }
	QToolTip(UINT id) : m_str( MAKEINTRESOURCE(id) )
	{ }
	operator LPCTSTR(){ return m_str; }

 

	QToolTip & operator =(HWND hWnd)
	{
		_window = hWnd;
		return *this;
	}

	bool Create(QWindow *hWndParent, QRect rect = QRect(), 
			LPCTSTR szWindowName = nullptr,
			DWORD dwStyle	= WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_USEVISUALSTYLE, 
			DWORD dwExStyle = WS_EX_TOPMOST,
			UINT MenuOrID	= 0U, 
			LPVOID lpCreateParam = nullptr)
	{
		bool bo =   CreateBaseWindowEx( 
			dwExStyle, GetWndClassName(), 
			szWindowName, dwStyle, 
			rect, hWndParent,  
			MenuOrID, GetModuleHandle(0), lpCreateParam);


		SetWindowPos(
			HWND_TOPMOST,
			0, 0, 0, 0,
			SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);


		return bo;

	}

// Attributes
	virtual LPCTSTR GetWndClassName()
	{
		return TOOLTIPS_CLASS;
	}

	void GetText(LPTOOLINFO lpToolInfo)
	{
		ASSERT( ::IsWindow(_window));
		SendMessage( TTM_GETTEXT, 0, (LPARAM)&lpToolInfo);
	}

	void GetText(LPTSTR lpstrText, HWND hWnd, UINT nIDTool = 0)  
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);
		QToolInfo ti(0, hWnd, nIDTool, nullptr, lpstrText);
		SendMessage( TTM_GETTEXT, 0, (LPARAM)&ti);
	}

	BOOL GetToolInfo(LPTOOLINFO lpToolInfo)  
	{
		ASSERT(::IsWindow(_window));
		return (BOOL) SendMessage(   TTM_GETTOOLINFO, 0, (LPARAM)lpToolInfo);
	}

	BOOL GetToolInfo(HWND hWnd, UINT nIDTool, UINT* puFlags, LPRECT lpRect, LPTSTR lpstrText)  
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);
		ASSERT(puFlags != nullptr);
		ASSERT(lpRect != nullptr);
		QToolInfo ti(0, hWnd, nIDTool, nullptr, lpstrText);
		BOOL bRet = (BOOL) SendMessage(  TTM_GETTOOLINFO, 0, (LPARAM)&ti);
		if(bRet != FALSE)
		{
			*puFlags = ti.uFlags;
			*lpRect = ti.rect;
		}
		return bRet;
	}

	void SetToolInfo(LPTOOLINFO lpToolInfo)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(  TTM_SETTOOLINFO, 0, (LPARAM)lpToolInfo);
	}

	void SetToolRect(LPTOOLINFO lpToolInfo)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(  TTM_NEWTOOLRECT, 0, (LPARAM)lpToolInfo);
	}

	void SetToolRect(HWND hWnd, UINT nIDTool, LPCRECT lpRect)
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);
		ASSERT(nIDTool != 0);

		QToolInfo ti(0, hWnd, nIDTool, (LPRECT)lpRect, nullptr);
		SendMessage(TTM_NEWTOOLRECT, 0, (LPARAM)&ti);
	}

	int GetToolCount()  
	{
		ASSERT(::IsWindow(_window));
		return (int)SendMessage(TTM_GETTOOLCOUNT, 0, 0L);
	}

	int GetDelayTime(DWORD dwType)  
	{
		ASSERT(::IsWindow(_window));
		return (int)SendMessage(TTM_GETDELAYTIME, dwType, 0L);
	}

	void SetDelayTime(DWORD dwType, int nTime)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_SETDELAYTIME, dwType, MAKELPARAM(nTime, 0));
	}

	void GetMargin(LPRECT lpRect)  
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_GETMARGIN, 0, (LPARAM)lpRect);
	}

	void SetMargin(LPRECT lpRect)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_SETMARGIN, 0, (LPARAM)lpRect);
	}

	int GetMaxTipWidth()  
	{
		ASSERT(::IsWindow(_window));
		return (int)SendMessage(TTM_GETMAXTIPWIDTH, 0, 0L);
	}

	int SetMaxTipWidth(int nWidth)
	{
		ASSERT(::IsWindow(_window));
		return (int)SendMessage(TTM_SETMAXTIPWIDTH, 0, nWidth);
	}

	COLORREF GetTipBkColor()  
	{
		ASSERT(::IsWindow(_window));
		return (COLORREF)SendMessage(TTM_GETTIPBKCOLOR, 0, 0L);
	}

	void SetTipBkColor(COLORREF clr)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_SETTIPBKCOLOR, (WPARAM)clr, 0L);
	}

	COLORREF GetTipTextColor()  
	{
		ASSERT(::IsWindow(_window));
		return (COLORREF)SendMessage(TTM_GETTIPTEXTCOLOR, 0, 0L);
	}

	void SetTipTextColor(COLORREF clr)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_SETTIPTEXTCOLOR, (WPARAM)clr, 0L);
	}

	BOOL GetCurrentTool(LPTOOLINFO lpToolInfo)  
	{
		ASSERT(::IsWindow(_window));
		return (BOOL)SendMessage(TTM_GETCURRENTTOOL, 0, (LPARAM)lpToolInfo);
	}

#if (_WIN32_IE >= 0x0500)
	SIZE GetBubbleSize(LPTOOLINFO lpToolInfo)  
	{
		ASSERT(::IsWindow(_window));
		DWORD dwRet = (DWORD)SendMessage(TTM_GETBUBBLESIZE, 0, (LPARAM)lpToolInfo);
		SIZE size = { LOWORD(dwRet), HIWORD(dwRet) };
		return size;
	}

	BOOL SetTitle(UINT uIcon, LPCTSTR lpstrTitle)
	{
		ASSERT(::IsWindow(_window));
		return (BOOL)SendMessage(TTM_SETTITLE, uIcon, (LPARAM)lpstrTitle);
	}
#endif // (_WIN32_IE >= 0x0500)

#if (_WIN32_WINNT >= 0x0501)
	void GetTitle(PTTGETTITLE pTTGetTitle)  
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_GETTITLE, 0, (LPARAM)pTTGetTitle);
	}

	void SetWindowTheme(LPCWSTR lpstrTheme)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_SETWINDOWTHEME, 0, (LPARAM)lpstrTheme);
	}
#endif // (_WIN32_WINNT >= 0x0501)

// Operations
	void Activate(BOOL bActivate = TRUE)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_ACTIVATE, bActivate );
	}

	BOOL AddTool(LPTOOLINFO lpToolInfo)
	{
		ASSERT(::IsWindow(_window));
		return (BOOL) SendMessage(  TTM_ADDTOOL,  0, (LPARAM) lpToolInfo );
	}

	BOOL AddTool(HWND hWnd, QString text = LPSTR_TEXTCALLBACK, LPCRECT lpRectTool = nullptr, UINT nIDTool = 0)
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);
		
		// the toolrect and toolid must both be zero or both valid
		//ASSERT((lpRectTool != nullptr && nIDTool != 0) || (lpRectTool == nullptr && nIDTool == 0));

		QToolInfo ti(TTF_SUBCLASS, hWnd, nIDTool, (LPRECT)lpRectTool, (LPTSTR)text);
		return (BOOL) SendMessage(  TTM_ADDTOOL, 0, (LPARAM)&ti);
	}

	void DelTool(LPTOOLINFO lpToolInfo)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(  TTM_DELTOOL, 0, (LPARAM)lpToolInfo);
	}

	void DelTool(HWND hWnd, UINT nIDTool = 0)
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);

		QToolInfo ti(0, hWnd, nIDTool, nullptr, nullptr);
		SendMessage( TTM_DELTOOL, 0, (LPARAM)&ti);
	}

	BOOL HitTest(LPTTHITTESTINFO lpHitTestInfo)  
	{
		ASSERT(::IsWindow(_window));
		return (BOOL) SendMessage(  TTM_HITTEST, 0, (LPARAM)lpHitTestInfo);
	}

	BOOL HitTest(HWND hWnd, POINT pt, LPTOOLINFO lpToolInfo)  
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);
		ASSERT(lpToolInfo != nullptr);

		TTHITTESTINFO hti = { 0 };
		hti.ti.cbSize = sizeof(TOOLINFO);
		hti.hwnd = hWnd;
		hti.pt.x = pt.x;
		hti.pt.y = pt.y;
		if((BOOL) SendMessage(  TTM_HITTEST, 0, (LPARAM)&hti) != FALSE)
		{
			*lpToolInfo = hti.ti;
			return TRUE;
		}
		return FALSE;
	}

	void RelayEvent(LPMSG lpMsg)
	{
		ASSERT(::IsWindow(_window));
		 SendMessage( TTM_RELAYEVENT, 0, (LPARAM)lpMsg);
	}

	void UpdateTipText(LPTOOLINFO lpToolInfo)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_UPDATETIPTEXT, 0, (LPARAM)lpToolInfo);
	}

	void UpdateTipText(QString text, HWND hWnd, UINT nIDTool = 0)
	{
		ASSERT(::IsWindow(_window));
		ASSERT(hWnd != nullptr);

		QToolInfo ti(0, hWnd, nIDTool, nullptr, (LPTSTR)text);
		SendMessage( TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
	}

	BOOL EnumTools(UINT nTool, LPTOOLINFO lpToolInfo)  
	{
		ASSERT(::IsWindow(_window));
		return (BOOL) SendMessage(  TTM_ENUMTOOLS, nTool, (LPARAM)lpToolInfo);
	}

	void Pop()
	{
		ASSERT(::IsWindow(_window));
		SendMessage(  TTM_POP, 0, 0L);
	}

	void TrackActivate( BOOL bActivate, HWND hWnd, UINT nIDTool = 0)
	{
		ASSERT(::IsWindow(_window));
		TOOLINFO ti = { sizeof(ti),  0,  hWnd, nIDTool };
		SendMessage( TTM_TRACKACTIVATE, bActivate, (LPARAM)&ti);
	}

	void TrackPosition(int xPos, int yPos)
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_TRACKPOSITION, 0, MAKELPARAM(xPos, yPos));
	}

#if (_WIN32_IE >= 0x0400)
	void Update()
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_UPDATE, 0, 0L);
	}
#endif // (_WIN32_IE >= 0x0400)

#if (_WIN32_IE >= 0x0500)
	BOOL AdjustRect(LPRECT lpRect, BOOL bLarger /*= TRUE*/)
	{
		ASSERT(::IsWindow(_window));
		return (BOOL)SendMessage(TTM_ADJUSTRECT, bLarger, (LPARAM)lpRect);
	}
#endif // (_WIN32_IE >= 0x0500)

#if (_WIN32_WINNT >= 0x0501)
	void Popup()
	{
		ASSERT(::IsWindow(_window));
		SendMessage(TTM_POPUP, 0, 0L);
	}
#endif // (_WIN32_WINNT >= 0x0501)




};

//typedef QToolTip ToolTip;

}
}//micro